#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QString>
#include <QThread>
#include <QDebug>
#include <QMetaType>

#include "pcap.h"
#include "winsock2.h"
#include "format.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

// 管理数据包类
class Data_Package
{
private:
	u_int data_length;
	QString time_stmp;
	QString data_package_info;
	int data_package_type;
public:
	const u_char *data_package_content_point;
protected:
	static QString byte_to_String(char *str, int size)
	{
		QString res = "";
		for(int i=0; i<size; i++)
		{
			char one = str[i] >> 4;
			if(one > 0x0A)
				one += 0x41 - 0x0A;
			else
				one += 0x30;
			char two = str[i] & 0xF;
			if(two > 0x0A)
				two += 0x41 - 0x0A;
			else
				two += 0x30;
			res.append(one);
			res.append(two);
		}
		return res;
	}
public:
	Data_Package()
	{
		qRegisterMetaType<Data_Package>("Data_Package");
		this->time_stmp = "";
		this->data_length = 0;
		this->data_package_type = 0;
	}

	// set成员函数
	void set_data_package_length(int data_length)
	{
		this->data_length = data_length;
	}
	void set_time_stmp(QString time_stmp)
	{
		this->time_stmp = time_stmp;
	}
	void set_data_package_type(int data_package_type);
	void set_data_package_content_point(const u_char *data_package_content, int size)
	{
		this->data_package_content_point = data_package_content;
		memcpy((char*)(this->data_package_content_point),(data_package_content),size);
	}
	void set_data_package_info(QString data_package_info)
	{
		this->data_package_info = data_package_info;
	}

	// get成员函数
	QString get_data_package_length()
	{
		return QString::number(this->data_length);
	}
	QString get_time_stmp()
	{
		return this->time_stmp;
	}
	QString get_data_package_type()
	{
		switch (this->data_package_type) {
		case 1: return "ARP";
		case 2: return "ICMP";
		case 3: return "TCP";
		case 4: return "UDP";
		case 5: return "DNS";
		case 6: return "TLS";
		case 7: return "SSL";
		default: return "";
		}
	}
	QString get_data_package_info()
	{
		return this->data_package_info;
	}
};

class MainWindow : public QMainWindow
{
	Q_OBJECT

public:
	MainWindow(QWidget *parent = nullptr);

	void show_networkcard();
	int capture();

	~MainWindow();

private slots:
	void on_comboBox_network_card_currentIndexChanged(int index);
public slots:
	void receive_data_package(Data_Package data_package)
	{
		qDebug() << data_package.get_time_stmp() << " " << data_package.get_data_package_info();
	}

private:
	Ui::MainWindow *ui;
	pcap_if_t *all_device;
	pcap_if_t *current_device;
	pcap_t *device_file_descriptor; // 网卡设备文件描述符
	char error_buffer[PCAP_ERRBUF_SIZE]; // 打开网卡出错信息
};

// 使用重写run方法实现多线程
class Multhread : public QThread
{
	Q_OBJECT
public:
	Multhread()
	{
		this->is_done = true;
	}
	bool set_device_file_descriptor(pcap_t *device_file_descriptor)
	{
		this->device_file_descriptor = device_file_descriptor;
		if(device_file_descriptor)
			return true;
		else
			return false;
	}
	void set_flag()
	{
		this->is_done = false;
	}
	void reset_flag()
	{
		this->is_done = true;
	}
	void run() override
	{
		while(true)
		{
			if(this->is_done)
				break;
			else
			{
				int result = pcap_next_ex(device_file_descriptor, &data_package_header, &data_package_content);
				if(result == 0)
					continue;
				else
				{
					// 此处时间戳不是标准的 可使用localtime_s()转换 把时间转换成字符串strftime()
					local_time_sec = data_package_header->ts.tv_sec;
					qDebug() << local_time_sec;
					QString data_package_info;
					int type = this->parse_data_ethernet(data_package_content, data_package_info);
					if(type)
					{
						Data_Package data_package;
						int len = data_package_header->len;
						data_package.set_data_package_info(data_package_info);
						data_package.set_data_package_length(len);
						data_package.set_time_stmp(QString::number(local_time_sec));
						emit send_data_package(data_package);
					}
				}
			}
		}
	}
	int parse_data_ethernet(const u_char *data_package_content, QString &data_package_info)
	{
		ETHER_HEADER *ethernet;
		u_short data_package_type;
		ethernet = (ETHER_HEADER*)(data_package_content);
		data_package_type = ntohs(ethernet->ether_type);
		switch (data_package_type) {
			case 0x800: { // ip
				data_package_info = "ip";
				return 1;
			}
			case 0x806: { // arp
				data_package_info = "arp";
				return 1;
			}
			default: break;
		}
	}
signals:
	void send_data_package(Data_Package data_package);

private:
	pcap_t *device_file_descriptor; // 网卡设备文件描述符
	struct pcap_pkthdr *data_package_header; // 数据包头部结构
	const u_char *data_package_content; // 数据包内容
	// 保存时间戳 不标准
	time_t local_time_sec;
	// 保存标准时间戳
	struct tm local_time;
	// 把时间戳转换字符串 用time_string存储
	char time_string[16];
	// 线程是否结束
	bool is_done;
};


#endif // MAINWINDOW_H

